use super::model::{module_name, User};
use crate::db;
use crate::model::state_code::{StateCode, StateCodeError};
use futures::TryStreamExt;
use mongodb::bson::doc;
use mongodb::bson::oid::ObjectId;

const COLLECTION_NAME: &str = "User";

/// 获取用户项
#[allow(unused)]
pub async fn get_all() -> Result<Vec<User>, StateCodeError> {
    let db_obj = db::mongo_db();
    let result = db_obj.collection(COLLECTION_NAME).find(doc! {}, None).await;
    match result {
        Ok(mut cur) => {
            let mut result: Vec<User> = Vec::new();
            loop {
                let item = cur.try_next().await;
                match item {
                    Ok(val) => {
                        if val.is_some() {
                            result.push(val.unwrap());
                        } else {
                            return Ok(result);
                        }
                    }
                    Err(err) => {
                        log_util::local_error!(
                            format!("{} get_all try_next error:", module_name()),
                            err.to_string()
                        )
                        .await;

                        return Err(StateCode::Error.into());
                    }
                }
            }
        }
        Err(err) => {
            log_util::local_error!(
                format!("{} get_item error:", module_name()),
                err.to_string()
            )
            .await;
            Err(StateCodeError::from_err(err))
        }
    }
}

/// 获取用户项
#[allow(unused)]
pub async fn get_item(id: &ObjectId) -> Result<Option<User>, StateCodeError> {
    let db_obj = db::mongo_db();
    let result = db_obj
        .collection(COLLECTION_NAME)
        .find_one(
            doc! {
                "_id":id
            },
            None,
        )
        .await;
    match result {
        Ok(val) => Ok(val),
        Err(err) => {
            log_util::local_error!(
                format!("{} get_item error:", module_name()),
                err.to_string()
            )
            .await;
            Err(StateCodeError::from_err(err))
        }
    }
}

/// 获取用户项
#[allow(unused)]
pub async fn get_item_by_name(name: String) -> Result<Option<User>, StateCodeError> {
    let db_obj = db::mongo_db();
    let result = db_obj
        .collection(COLLECTION_NAME)
        .find_one(
            doc! {
                "name":name
            },
            None,
        )
        .await;
    match result {
        Ok(val) => Ok(val),
        Err(err) => {
            log_util::local_error!(
                format!("{} get_item_by_name error:", module_name()),
                err.to_string()
            )
            .await;
            Err(StateCodeError::from_err(err))
        }
    }
}

/// 写入数据库
#[allow(unused)]
pub async fn insert(model_obj: &User) -> Result<(), StateCode> {
    let result = mongodb::bson::to_document(model_obj);
    let bson_obj;
    match result {
        Ok(val) => bson_obj = val,
        Err(err) => {
            log_util::local_error!("insert to_bson error", err.to_string()).await;
            return Err(StateCode::Error);
        }
    }

    let db_obj = db::mongo_db();
    let result = db_obj
        .collection(COLLECTION_NAME)
        .insert_one(bson_obj, None)
        .await;
    match result {
        Ok(_) => Ok(()),
        Err(err) => {
            log_util::local_error!(format!("{} insert error:", module_name()), err.to_string())
                .await;
            Err(StateCode::Error)
        }
    }
}
/// 写入数据库
#[allow(unused)]
pub async fn update(model_obj: &User) -> Result<(), StateCode> {
    let result = mongodb::bson::to_document(model_obj);
    let bson_obj;
    match result {
        Ok(val) => bson_obj = val,
        Err(err) => {
            log_util::local_error!("update to_bson error", err.to_string()).await;
            return Err(StateCode::Error);
        }
    }

    let db_obj = db::mongo_db();
    let result = db_obj
        .collection::<User>(COLLECTION_NAME)
        .update_one(
            doc! {
                "_id":model_obj.id.clone(),
            },
            doc! {
                "$set":bson_obj
            },
            None,
        )
        .await;
    match result {
        Ok(_) => Ok(()),
        Err(err) => {
            log_util::local_error!(format!("{} update error:", module_name()), err.to_string())
                .await;
            Err(StateCode::Error)
        }
    }
}

/// 更新数据库
#[allow(unused)]
pub async fn update_login_info(
    id: ObjectId,
    last_login_time: i64,
    last_login_ip: String,
) -> Result<(), StateCode> {
    let db_obj = db::mongo_db();
    let result = db_obj
        .collection::<User>(COLLECTION_NAME)
        .update_one(
            doc! {
                "_id":id,
            },
            doc! {
                "$set":{
                    "LastLoginTime":last_login_time,
                    "LastLoginIp":last_login_ip,
                }
            },
            None,
        )
        .await;
    match result {
        Ok(_) => Ok(()),
        Err(err) => {
            log_util::local_error!(
                format!("{} update_login_info error:", module_name()),
                err.to_string()
            )
            .await;
            Err(StateCode::Error)
        }
    }
}
